package com.qiaofang.applet.service.other.service.impl;

import com.google.common.collect.Lists;
import com.qiaofang.applet.common.base.MongoBaseService;
import com.qiaofang.applet.common.context.QfContextHolder;
import com.qiaofang.applet.common.exception.BusinessException;
import com.qiaofang.applet.common.util.CustomUtil;
import com.qiaofang.applet.service.other.domain.Assets;
import com.qiaofang.applet.service.other.domain.AssetsType;
import com.qiaofang.applet.service.other.domain.DictCorp;
import com.qiaofang.applet.service.other.repository.AssetsRepository;
import com.qiaofang.applet.service.other.repository.AssetsTypeRepository;
import com.qiaofang.applet.service.other.repository.DictCorpRepository;
import com.qiaofang.applet.service.other.service.AssetsService;
import com.qiaofang.applet.service.other.service.CityCompanyService;
import com.qiaofang.applet.service.other.service.DictCorpService;
import com.qiaofang.applet.service.other.service.WxaQrCodeService;
import com.qiaofang.applet.service.other.service.dto.*;
import com.qiaofang.applet.service.other.service.mapstruct.AssetsMapper;
import com.qiaofang.applet.service.other.service.mapstruct.AssetsTypeMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author daiyuxiang
 */
@Slf4j
@Service
public class AssetsServiceImpl extends MongoBaseService<Assets, String> implements AssetsService {

    private final AssetsRepository repository;

    @Autowired
    private AssetsMapper assetsMapper;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private AssetsTypeRepository typeRepository;

    @Autowired
    private AssetsTypeMapper assetsTypeMapper;

    @Autowired
    private CityCompanyService cityCompanyService;

    @Autowired
    private WxaQrCodeService wxaQrCodeService;

    @Autowired
    private DictCorpRepository dictCorpRepository;

    @Autowired
    public AssetsServiceImpl(AssetsRepository repository) {
        super(repository);
        this.repository = repository;
    }

    /**
     * 资讯列表查询(小程序和pc官网用)
     *
     * @param queryDto
     * @param pageable
     * @return
     */
    @Override
    public Page<AssetsDetailDto> getListForClient(AssetsQueryDto queryDto, Pageable pageable) {
        String cityCode = queryDto.getCityCode();
        String assetsTypeId = queryDto.getAssetsTypeId();
        Query query = new Query();
        query.addCriteria(Criteria.where("corporationCode").is(QfContextHolder.getContext().getCorporationCode()));
        if (StringUtils.isNotEmpty(cityCode)) {
            query.addCriteria(Criteria.where("cityCodes").in(cityCode));
        }
        if (StringUtils.isNotEmpty(assetsTypeId)) {
            query.addCriteria(Criteria.where("assetsTypeId").is(assetsTypeId));
        }

        long count = mongoTemplate.count(query.with(pageable), Assets.class);
        query.with(Sort.by(Sort.Order.desc("updateTime")));
        List<Assets> assets = null;
        if (count > 0) {
            assets = mongoTemplate.find(query.with(pageable), Assets.class);
        }
        List<AssetsDetailDto> assetsDetailDtos = convertDomain2DTO(assets);
        // 查询城市名称、资讯分类名称
        initCityNameAndAssetsType(QfContextHolder.getContext().getCorporationCode(), assetsDetailDtos);
        return PageableExecutionUtils.getPage(assetsDetailDtos, pageable, () -> count);
    }

    /**
     * 资讯列表查询
     *
     * @param requestDto
     * @param pageable
     * @return
     */
    @Override
    public Page<AssetsDetailDto> findByParams(AssetsRequestDto requestDto, Pageable pageable) {
        String cityCode = requestDto.getCityCode();
        String titleOrContent = requestDto.getTitleOrContent();
        String assetsTypeId = requestDto.getAssetsTypeId();
        Timestamp beginDate = requestDto.getBeginDate();
        Timestamp endDate = requestDto.getEndDate();
        Query query = new Query();
        query.addCriteria(Criteria.where("corporationCode").is(requestDto.getCorporationCode()));
        if (StringUtils.isNotEmpty(cityCode)) {
            query.addCriteria(Criteria.where("cityCodes").in(cityCode));
        } else if (!CollectionUtils.isEmpty(requestDto.getCityCodes())){
            query.addCriteria(Criteria.where("cityCodes").in(requestDto.getCityCodes()));
        }
        if (StringUtils.isNotEmpty(titleOrContent)) {
//            Criteria criteria = new Criteria();
//            criteria.orOperator(Criteria.where("assetsTitle").regex(".*?" + titleOrContent + ".*"),
//                    Criteria.where("assetsContent").regex(".*?" + titleOrContent + ".*"));
            query.addCriteria(Criteria.where("assetsTitle").regex(".*?" + titleOrContent + ".*"));
        }
        if (StringUtils.isNotEmpty(assetsTypeId)) {
            query.addCriteria(Criteria.where("assetsTypeId").is(assetsTypeId));
        }
        if (beginDate != null && endDate != null) {
            query.addCriteria(Criteria.where("updateTime").gte(beginDate).lt(endDate));
        }
        long count = mongoTemplate.count(query.with(pageable), Assets.class);
        List<Assets> assets = new ArrayList<>();
        if (count > 0) {
            assets = mongoTemplate.find(query.with(pageable), Assets.class);
        }
        List<AssetsDetailDto> assetsDetailDtos = assetsMapper.toDto(assets);
        // 查询城市名称、资讯分类名称
        initCityNameAndAssetsType(requestDto.getCorporationCode(), assetsDetailDtos);
        return PageableExecutionUtils.getPage(assetsDetailDtos, pageable, () -> count);
    }

    /**
     * 初始化城市和咨询分类
     *
     * @param corporationCode
     * @param assetsDetailDtos
     */
    private void initCityNameAndAssetsType(String corporationCode, List<AssetsDetailDto> assetsDetailDtos) {
        if (CollectionUtils.isEmpty(assetsDetailDtos)) {
            return;
        }

        List<AssetsType> assetsTypes = typeRepository.findAllByCorporationCode(corporationCode);
        // 资讯类别集合
        Map<String, String> assetsTypeMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(assetsTypes)) {
            assetsTypes.parallelStream().forEach(assetsType -> {
                assetsTypeMap.put(assetsType.getId(), assetsType.getAssetsTypeName());
            });
        }

        List<CityDesDto> cityDesDtos = cityCompanyService.getCityList(corporationCode);
        // 城市集合
        Map<String, String> cityMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(cityDesDtos)) {
            cityDesDtos.parallelStream().forEach(cityDesDto -> {
                cityMap.put(cityDesDto.getCityCode(), cityDesDto.getCityName());
            });
        }

        StringBuilder cityNames;
        for (AssetsDetailDto assetsDetailDto : assetsDetailDtos) {
            cityNames = new StringBuilder();
            assetsDetailDto.setAssetsTypeName(StringUtils.defaultString(assetsTypeMap.get(assetsDetailDto.getAssetsTypeId())));
            if (CollectionUtils.isEmpty(assetsDetailDto.getCityCodes())) {
                continue;
            }

            for (String cityCode : assetsDetailDto.getCityCodes()) {
                cityNames.append(StringUtils.defaultString(cityMap.get(cityCode))).append(",");
            }

            int len = cityNames.length();
            assetsDetailDto.setCityNames(len > 0 ? cityNames.substring(0, len - 1) : "");
        }
    }

    private List<AssetsDetailDto> convertDomain2DTO(List<Assets> assetsList) {
        if (assetsList == null) {
            return new ArrayList<>();
        }
        List<AssetsDetailDto> list = new ArrayList<>(assetsList.size());
        for (Assets assets : assetsList) {
            AssetsDetailDto dto = new AssetsDetailDto();
            dto.setId(assets.getId());
            dto.setCityCodes(assets.getCityCodes());
            dto.setAssetsTitle(assets.getAssetsTitle());
            //清除html样式
            String htmlStr = CustomUtil.StripHT(assets.getAssetsContent());
            if (StringUtils.isNotBlank(htmlStr) && htmlStr.length() > 200) {
                dto.setAssetsContent(htmlStr.substring(0, 199));
            } else {
                dto.setAssetsContent(htmlStr);
            }
            dto.setUpdateTime(assets.getUpdateTime());
            dto.setAssetsTypeId(assets.getAssetsTypeId());
            //设置图片
            List<String> img = CustomUtil.extractImg(assets.getAssetsContent());
            if (!img.isEmpty()) {
                dto.setAssetsImg(img.get(0));
            }
            if (StringUtils.isNotBlank(assets.getAssetsUrl())) {
                dto.setAssetsUrl(assets.getAssetsUrl());
            } else {
                dto.setAssetsUrl("");
            }
            list.add(dto);
        }
        return list;
    }

    /**
     * 保存资讯详情，包括新增和编辑
     *
     * @param assets
     */
    @Override
    public void saveAssets(Assets assets) {
        if (StringUtils.isEmpty(assets.getId())) {
            assets.setId(ObjectId.get().toString());
            repository.insert(assets);
        } else {
            updateById(assets);
        }
    }

    /**
     * 删除资讯
     *
     * @param assetsId
     */
    @Override
    public void removeAssets(String assetsId) {
        repository.deleteById(assetsId);
    }

    /**
     * 保存资讯类型
     *
     * @param assetsType
     */
    @Override
    public void saveAssetsType(AssetsType assetsType) {
        if (StringUtils.isEmpty(assetsType.getId())) {
            assetsType.setId(ObjectId.get().toString());
            typeRepository.insert(assetsType);
        } else {
            Query query = new Query(Criteria.where("id").is(assetsType.getId()));
            Update update = new Update().set("assetsTypeName", assetsType.getAssetsTypeName());
            mongoTemplate.update(AssetsType.class)
                    .matching(query)
                    .apply(update)
                    .withOptions(FindAndModifyOptions.options().returnNew(true))
                    .findAndModifyValue();
        }
    }

    /**
     * 删除资讯类型
     *
     * @param assetsTypeId
     */
    @Override
    public void removeAssetsType(String assetsTypeId) {
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("corporationCode", match -> match.exact())
                .withIgnoreNullValues();
        Assets assets = new Assets();
        assets.setAssetsTypeId(assetsTypeId);
        if (repository.exists(Example.of(assets, matcher))) {
            throw new BusinessException("该资讯类别下有关联的咨讯，请先删除对应的资讯");
        }
        typeRepository.deleteById(assetsTypeId);
    }

    /**
     * 资讯类型分页查询
     *
     * @param assetsTypeDto
     * @param pageable
     * @return
     */
    @Override
    public Page<AssetsTypeDto> findTypeByParams(AssetsTypeDto assetsTypeDto, Pageable pageable) {
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("assetsTypeName", match -> match.contains())
                .withMatcher("corporationCode", match -> match.exact())
                .withIgnoreNullValues();
        AssetsType assetsType = new AssetsType();
        assetsType.setAssetsTypeName(assetsTypeDto.getAssetsTypeName());
        assetsType.setCorporationCode(assetsTypeDto.getCorporationCode());
        Page<AssetsType> result = typeRepository.findAll(Example.of(assetsType, matcher), pageable);
        return result.map(assetsTypeMapper::toDto);
    }

    /**
     * 获取全部资讯类型（下拉框用）
     *
     * @return
     */
    @Override
    public List<AssetsTypeDto> findAllType(String corporationCode) {
        return assetsTypeMapper.toDto(typeRepository.findAllByCorporationCode(corporationCode));
    }

    @Override
    public List<List<AssetsDetailDto>> getIndexAssets(String cityCode, Pageable pageable) {
        Query query = new Query();
        query.addCriteria(Criteria.where("corporationCode").is(QfContextHolder.getContext().getCorporationCode()));
        if (StringUtils.isNotEmpty(cityCode)) {
            query.addCriteria(Criteria.where("cityCodes").in(cityCode));
        } else {
            throw new BusinessException("城市code不能为空");
        }
        long count = mongoTemplate.count(query, Assets.class);
        query.with(Sort.by(Sort.Order.desc("updateTime")));
        List<Assets> assets = null;
        if (count > 0){
            assets = mongoTemplate.find(query.with(pageable), Assets.class).stream().limit(9).collect(Collectors.toList());
            for (Assets asset : assets) {
                //清除html样式
                asset.setAssetsContent(CustomUtil.StripHT(asset.getAssetsContent()));
            }
        }
        List<AssetsDetailDto> detailDtoList = Optional.ofNullable(assets).orElseGet(Lists::newArrayList)
                .stream().map(assetsMapper::toDto).collect(Collectors.toList());
        //获取集团首页资讯行数设置
        DictCorp dictCorp = dictCorpRepository.findFirstByCorporationCodeAndDictType(QfContextHolder.getContext().getCorporationCode(), "index_page");
        if (dictCorp == null) {
            throw new BusinessException("该轮播资讯字典不存在");
        }
        return Lists.partition(detailDtoList, StringUtils.isNotBlank(dictCorp.getSubtitleData()) ? Integer.valueOf(dictCorp.getSubtitleData()) : 3);
    }

    @Override
    public ShareAssetsDto shareAssets(String id) {

        ShareAssetsDto shareAssetsDto = null;
        try {
            shareAssetsDto = new ShareAssetsDto();
            //文本
            String corporationCode = QfContextHolder.getContext().getCorporationCode();
            Assets assets = repository.findAssetsByCorporationCodeAndId(corporationCode, id);
            if (assets == null){
                throw new BusinessException("资讯不存在");
            }
            AssetsDetailDto assetsDetailDto = assetsMapper.toDto(assets);
            //清除html样式
            String htmlStr = CustomUtil.StripHT(assetsDetailDto.getAssetsContent());
            if (StringUtils.isNotBlank(htmlStr) && htmlStr.length() > 300) {
                shareAssetsDto.setAssetsContent(htmlStr.substring(0, 299));
            } else {
                shareAssetsDto.setAssetsContent(htmlStr);
            }
            //图片url
            List<String> photoUrls = CustomUtil.extractImg(assetsDetailDto.getAssetsContent());
            if (!CollectionUtils.isEmpty(photoUrls)){
                shareAssetsDto.setPhotoUrl(photoUrls.get(0));
            }
            //二维码
            shareAssetsDto.setQRcodeUrl(wxaQrCodeService.createQrCodeToShare(id));
        } catch (BusinessException e) {
            log.error("生成分享内容失败 {}", e);
        }
        return shareAssetsDto;
    }

    @Override
    public AssetsType findAssetsType(String id) {
        return typeRepository.findById(id).get();
    }

    @Override
    public List<String> getAssetsPhotoLists(String id) {
        String corporationCode = QfContextHolder.getContext().getCorporationCode();

        Assets assets = repository.findAssetsByCorporationCodeAndId(corporationCode, id);

        if (assets == null){
            throw new BusinessException("资讯不存在");
        }
        AssetsDetailDto assetsDetailDto = assetsMapper.toDto(assets);
        List<String> photoList = new ArrayList<>();
        try {
            photoList = CustomUtil.extractImg(assetsDetailDto.getAssetsContent());
        } catch (Exception e) {
            log.error("");
        }
        return photoList;
    }
}
